home *** CD-ROM | disk | FTP | other *** search
- {$A-,B-,D+,E-,F-,G+,I-,L+,N-,O-,R-,S-,V-,X+} {TP 6.0 & 286 required!}
- Unit x320x240;
-
- {
- Sean Palmer, 1993
- released to the Public Domain
- in tweaked modes, each latch/bit plane contains the entire 8-bit pixel.
- the sequencer map mask determines which plane (pixel) to update, and, when
- reading, the read map select reg determines which plane (pixel) to read.
- almost exactly opposite from regular vga 16-color modes which is why I never
- could get my routines to work For BOTH modes. 8)
-
- # = source screen pixel
- Normal 16-color Tweaked 256-color
-
- Bit Mask Bit Mask
- 76543210 33333333
- Map 76543210 Map 22222222
- Mask 76543210 Mask 11111111
- 76543210 00000000
-
- Functional equivalents
- Bit Mask = Seq Map Mask
- Seq Map Mask = Bit Mask
- }
-
-
- Interface
-
- Var
- color : Byte;
-
- Const
- xRes = 320;
- yRes = 240; {displayed screen size}
- xMax = xRes - 1;
- yMax = yRes - 1;
- xMid = xMax div 2;
- yMid = yMax div 2;
- vxRes = 512;
- vyRes = $40000 div vxRes; {virtual screen size}
- nColors = 256;
- tsx : Byte = 8;
- tsy : Byte = 8; {tile size}
-
-
- Procedure plot(x, y : Integer);
- Function scrn(x, y : Integer) : Byte;
-
- Procedure hLin(x, x2, y : Integer);
- Procedure vLin(x, y, y2 : Integer);
- Procedure rect(x, y, x2, y2 : Integer);
- Procedure pane(x, y, x2, y2 : Integer);
-
- Procedure line(x, y, x2, y2 : Integer);
- Procedure oval(xc, yc, a, b : Integer);
- Procedure disk(xc, yc, a, b : Integer);
- Procedure fill(x, y : Integer);
-
- Procedure putTile(x, y : Integer; p : Pointer);
- Procedure overTile(x, y : Integer; p : Pointer);
- Procedure putChar(x, y : Integer; p : Word);
-
- Procedure setColor(color, r, g, b : Byte);
- {rgb vals are from 0-63}
- Function getColor(color : Byte) : LongInt;
- {returns $00rrggbb format}
- Procedure setPalette(color : Byte; num : Word; Var rgb);
- {rgb is list of 3-Byte rgb vals}
- Procedure getPalette(color : Byte; num : Word; Var rgb);
-
- Procedure clearGraph;
- Procedure setWriteMode(f : Byte);
- Procedure waitRetrace;
- Procedure setWindow(x, y : Integer);
-
- {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
-
- Implementation
-
- Const
- vSeg = $A000; {video segment}
- vxBytes = vxRes div 4; {Bytes per virtual scan line}
- seqPort = $3C4; {Sequencer}
- gcPort = $3CE; {Graphics Controller}
- attrPort = $3C0; {attribute Controller}
-
- tableReadIndex = $3C7;
- tableWriteIndex = $3C8;
- tableDataRegister = $3C9;
-
- CrtcRegLen = 10;
- CrtcRegTable : Array [1..CrtcRegLen] of Word =
- ($0D06, $3E07, $4109, $EA10, $AC11, $DF12, $0014, $E715, $0616, $E317);
-
-
-
- Var
- CrtcPort : Word; {Crt controller}
- oldMode : Byte;
- ExitSave : Pointer;
- input1Port : Word; {Crtc Input Status Reg #1=CrtcPort+6}
- fillVal : Byte;
-
- Type
- tRGB = Record
- r, g, b : Byte;
- end;
-
- {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
-
- Procedure clearGraph; Assembler;
- Asm
- mov ax, vSeg
- mov es, ax
- mov dx, seqPort
- mov ax, $0F02
- out dx, ax {enable whole map mask}
- xor di, di
- mov cx, $8000 {screen size in Words}
- cld
- mov al, color
- mov ah, al
- repz stosw {clear screen}
- end;
-
- Procedure setWriteMode(f : Byte); Assembler;
- Asm {copy/and/or/xor modes}
- mov ah, f
- shl ah, 3
- mov al, 3
- mov dx, gcPort
- out dx, ax {Function select reg}
- end;
-
- Procedure waitRetrace; Assembler;
- Asm
- mov dx, CrtcPort
- add dx, 6 {find Crt status reg (input port #1)}
- @L1:
- in al, dx
- test al, 8
- jnz @L1; {wait For no v retrace}
- @L2:
- in al, dx
- test al, 8
- jz @L2 {wait For v retrace}
- end;
-
-
- {
- Since a virtual screen can be larger than the actual screen, scrolling is
- possible. This routine sets the upper left corner of the screen to the
- specified pixel. Make sure 0 <= x <= vxRes - xRes, 0 <= y <= vyRes - yRes
- }
- Procedure setWindow(x, y : Integer); Assembler;
- Asm
- mov ax, vxBytes
- mul y
- mov bx, x
- mov cl, bl
- shr bx, 2
- add bx, ax {bx=Ofs of upper left corner}
- mov dx, input1Port
- @L:
- in al, dx
- test al, 8
- jnz @L {wait For no v retrace}
- sub dx, 6 {CrtC port}
- mov al, $D
- mov ah, bl
- cli {these values are sampled at start of retrace}
- out dx, ax {lo Byte of display start addr}
- dec al
- mov ah, bh
- out dx, ax {hi Byte}
- sti
- add dx, 6
- @L2:
- in al, dx
- test al, 8
- jz @L2 {wait For v retrace}
- {this also resets Attrib flip/flop}
- mov dx, attrPort
- mov al, $33
- out dx, al {Select Pixel Pan Register}
- and cl, 3
- mov al, cl
- shl al, 1
- out dx, al {Shift is For 256 Color Mode}
- end;
-
- {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
-
- Procedure plot(x, y : Integer); Assembler;
- Asm
- mov ax, vSeg
- mov es, ax
- mov di, x
- mov cx, di
- shr di, 2
- mov ax, vxBytes
- mul y
- add di, ax
- mov ax, $0102
- and cl, 3
- shl ah, cl
- mov dx, seqPort
- out dx, ax {set bit mask}
- mov al, color
- stosb
- end;
-
- Function scrn(x, y : Integer) : Byte; Assembler;
- Asm
- mov ax, vSeg
- mov es, ax
- mov di, x
- mov cx, di
- shr di, 2
- mov ax, vxBytes
- mul y
- add di, ax
- and cl, 3
- mov ah, cl
- mov al, 4
- mov dx, gcPort
- out dx, ax {Read Map Select register}
- mov al, es:[di] {get the whole plane}
- end;
-
- Procedure hLin(x, x2, y : Integer); Assembler;
- Asm
- mov ax, vSeg
- mov es, ax
- cld
- mov ax, vxBytes
- mul y
- mov di, ax {base of scan line}
- mov bx, x
- mov cl, bl
- shr bx, 2
- mov dx, x2
- mov ch, dl
- shr dx, 2
- and cx, $0303
- sub dx, bx {width in Bytes}
- add di, bx {offset into video buffer}
- mov ax, $FF02
- shl ah, cl
- and ah, $0F {left edge mask}
- mov cl, ch
- mov bh, $F1
- rol bh, cl
- and bh, $0F {right edge mask}
- mov cx, dx
- or cx, cx
- jnz @LEFT
- and ah, bh {combine left & right bitmasks}
- @LEFT:
- mov dx, seqPort
- out dx, ax
- inc dx
- mov al, color
- stosb
- jcxz @EXIT
- dec cx
- jcxz @RIGHT
- mov al, $0F
- out dx, al {skipped if cx=0,1}
- mov al, color
- repz stosb {fill middle Bytes}
- @RIGHT:
- mov al, bh
- out dx, al {skipped if cx=0}
- mov al, color
- stosb
- @EXIT:
- end;
-
- Procedure vLin(x, y, y2 : Integer); Assembler;
- Asm
- mov ax, vSeg
- mov es, ax
- cld
- mov di, x
- mov cx, di
- shr di, 2
- mov ax, vxBytes
- mul y
- add di, ax
- mov ax, $102
- and cl, 3
- shl ah, cl
- mov dx, seqPort
- out dx, ax
- mov cx, y2
- sub cx, y
- inc cx
- mov al, color
- @DOLINE:
- mov bl, es:[di]
- stosb
- add di, vxBytes-1
- loop @DOLINE
- end;
-
- Procedure rect(x, y, x2, y2 : Integer);
- Var
- i : Word;
- begin
- hlin(x, pred(x2), y);
- hlin(succ(x), x2, y2);
- vlin(x, succ(y), y2);
- vlin(x2, y, pred(y2));
- end;
-
- Procedure pane(x, y, x2, y2 : Integer);
- Var
- i : Word;
- begin
- For i := y2 downto y do
- hlin(x, x2, i);
- end;
-
- Procedure line(x, y, x2, y2:Integer);
- Var
- d, dx, dy,
- ai, bi, xi, yi : Integer;
- begin
- if(x < x2) then
- begin
- xi := 1;
- dx := x2 - x;
- end
- else
- begin
- xi := -1;
- dx := x - x2;
- end;
- if (y < y2) then
- begin
- yi := 1;
- dy := y2 - y;
- end
- else
- begin
- yi := -1;
- dy := y - y2;
- end;
- plot(x, y);
- if dx > dy then
- begin
- ai := (dy - dx) * 2;
- bi := dy * 2;
- d := bi - dx;
- Repeat
- if (d >= 0) then
- begin
- inc(y, yi);
- inc(d, ai);
- end
- else
- inc(d, bi);
- inc(x, xi);
- plot(x, y);
- Until (x = x2);
- end
- else
- begin
- ai := (dx - dy) * 2;
- bi := dx * 2;
- d := bi - dy;
- Repeat
- if (d >= 0) then
- begin
- inc(x, xi);
- inc(d, ai);
- end
- else
- inc(d, bi);
- inc(y, yi);
- plot(x, y);
- Until (y = y2);
- end;
- end;
-
- Procedure oval(xc, yc, a, b : Integer);
- Var
- x, y : Integer;
- aa, aa2,
- bb, bb2,
- d, dx, dy : LongInt;
- begin
- x := 0;
- y := b;
- aa := LongInt(a) * a;
- aa2 := 2 * aa;
- bb := LongInt(b) * b;
- bb2 := 2 * bb;
- d := bb - aa * b + aa div 4;
- dx := 0;
- dy := aa2 * b;
- plot(xc, yc - y);
- plot(xc, yc + y);
- plot(xc - a, yc);
- plot(xc + a, yc);
- While (dx < dy) do
- begin
- if(d > 0) then
- begin
- dec(y);
- dec(dy, aa2);
- dec(d, dy);
- end;
- inc(x);
- inc(dx, bb2);
- inc(d, bb + dx);
- plot(xc + x, yc + y);
- plot(xc - x, yc + y);
- plot(xc + x, yc - y);
- plot(xc - x, yc - y);
- end;
-
- inc(d, (3 * (aa - bb) div 2 - (dx + dy)) div 2);
-
- While (y > 0) do
- begin
- if (d < 0) then
- begin
- inc(x);
- inc(dx, bb2);
- inc(d, bb + dx);
- end;
- dec(y);
- dec(dy, aa2);
- inc(d, aa - dy);
- plot(xc + x, yc + y);
- plot(xc - x, yc + y);
- plot(xc + x, yc - y);
- plot(xc - x, yc - y);
- end;
- end;
-
- Procedure disk(xc, yc, a, b:Integer);
- Var
- x, y : Integer;
- aa, aa2,
- bb, bb2,
- d, dx, dy : LongInt;
- begin
- x := 0;
- y := b;
- aa := LongInt(a) * a;
- aa2 := 2 * aa;
- bb := LongInt(b) * b;
- bb2 := 2 * bb;
- d := bb - aa * b + aa div 4;
- dx := 0;
- dy := aa2 * b;
-
- vLin(xc, yc - y, yc + y);
-
- While (dx < dy) do
- begin
- if (d > 0) then
- begin
- dec(y);
- dec(dy, aa2);
- dec(d, dy);
- end;
- inc(x);
- inc(dx, bb2);
- inc(d, bb + dx);
- vLin(xc - x, yc - y, yc + y);
- vLin(xc + x, yc - y, yc + y);
- end;
-
- inc(d, (3 * (aa - bb) div 2 - (dx + dy)) div 2);
-
- While (y >= 0) do
- begin
- if (d < 0) then
- begin
- inc(x);
- inc(dx, bb2);
- inc(d, bb + dx);
- vLin(xc - x, yc - y, yc + y);
- vLin(xc + x, yc - y, yc + y);
- end;
- dec(y);
- dec(dy, aa2);
- inc(d, aa - dy);
- end;
- end;
-
- {This routine only called by fill}
- Function lineFill(x, y, d, prevXL, prevXR : Integer) : Integer;
- Var
- xl, xr, i : Integer;
- Label
- _1, _2, _3;
- begin
- xl := x;
- xr := x;
-
- Repeat
- dec(xl);
- Until (scrn(xl, y) <> fillVal) or (xl < 0);
-
- inc(xl);
-
- Repeat
- inc(xr);
- Until (scrn(xr, y) <> fillVal) or (xr > xMax);
-
- dec(xr);
- hLin(xl, xr, y);
- inc(y, d);
-
- if Word(y) <= yMax then
- For x := xl to xr do
- if (scrn(x, y) = fillVal) then
- begin
- x := lineFill(x, y, d, xl, xr);
- if Word(x) > xr then
- Goto _1;
- end;
-
- _1 :
-
- dec(y, d + d);
- Asm
- neg d;
- end;
- if Word(y) <= yMax then
- begin
- For x := xl to prevXL do
- if (scrn(x, y) = fillVal) then
- begin
- i := lineFill(x, y, d, xl, xr);
- if Word(x) > prevXL then
- Goto _2;
- end;
-
- _2 :
-
- for x := prevXR to xr do
- if (scrn(x, y) = fillVal) then
- begin
- i := lineFill(x, y, d, xl, xr);
- if Word(x) > xr then
- Goto _3;
- end;
-
- _3 :
-
- end;
-
- lineFill := xr;
- end;
-
- Procedure fill(x, y : Integer);
- begin
- fillVal := scrn(x, y);
- if fillVal <> color then
- lineFill(x, y, 1, x, x);
- end;
-
-
- {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
-
- Procedure putTile(x, y : Integer; p : Pointer); Assembler;
- Asm
- push ds
- lds si, p
- mov ax, vSeg
- mov es, ax
- mov di, x
- mov cx, di
- shr di, 2
- mov ax, vxBytes
- mul y
- add di, ax
- mov ax, $102
- and cl, 3
- shl ah, cl {make bit mask}
- mov dx, seqPort
- mov bh, tsy
- @DOLINE:
- mov cl, tsx
- xor ch, ch
- push ax
- push di {save starting bit mask}
- @LOOP:
- {mov al, 2}
- out dx, ax
- shl ah, 1 {give it some time to respond}
- mov bl, es:[di]
- movsb
- dec di
- test ah, $10
- jz @SAMEByte
- mov ah, 1
- inc di
- @SAMEByte:
- loop @LOOP
- pop di
- add di, vxBytes
- pop ax {start of next line}
- dec bh
- jnz @DOLINE
- pop ds
- end;
-
- Procedure overTile(x, y : Integer; p : Pointer); Assembler;
- Asm
- push ds
- lds si, p
- mov ax, vSeg
- mov es, ax
- mov di, x
- mov cx, di
- shr di, 2
- mov ax, vxBytes
- mul y
- add di, ax
- mov ax, $102
- and cl, 3
- shl ah, cl {make bit mask}
- mov bh, tsy
- mov dx, seqPort
- @DOLINE:
- mov ch, tsx
- push ax
- push di {save starting bit mask}
- @LOOP:
- mov al, 2
- mov dx, seqPort
- out dx, ax
- shl ah, 1
- xchg ah, cl
- mov al, 4
- mov dl, gcPort and $FF
- out dx, ax
- xchg ah, cl
- inc cl
- and cl, 3
- lodsb
- or al, al
- jz @SKIP
- mov bl, es:[di]
- cmp bl, $C0
- jae @SKIP
- stosb
- dec di
- @SKIP:
- test ah, $10
- jz @SAMEByte
- mov ah, 1
- inc di
- @SAMEByte:
- dec ch
- jnz @LOOP
- pop di
- add di, vxBytes
- pop ax {start of next line}
- dec bh
- jnz @DOLINE
- pop ds
- end;
-
- {won't handle Chars wider than 1 Byte}
- Procedure putChar(x, y : Integer; p : Word); Assembler;
- Asm
- mov si, p {offset of Char in DS}
- mov ax, vSeg
- mov es, ax
- mov di, x
- mov cx, di
- shr di, 2
- mov ax, vxBytes
- mul y
- add di, ax
- mov ax, $0102
- and cl, 3
- shl ah, cl {make bit mask}
- mov dx, seqPort
- mov cl, tsy
- xor ch, ch
- @DOLINE:
- mov bl, [si]
- inc si
- push ax
- push di {save starting bit mask}
- @LOOP:
- mov al, 2
- out dx, ax
- shl ah, 1
- shl bl, 1
- jnc @SKIP
- mov al, color
- mov es:[di], al
- @SKIP:
- test ah, $10
- jz @SAMEByte
- mov ah, 1
- inc di
- @SAMEByte:
- or bl, bl
- jnz @LOOP
- pop di
- add di, vxBytes
- pop ax {start of next line}
- loop @DOLINE
- end;
-
- {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
-
- Procedure setColor(color, r, g, b : Byte); Assembler;
- Asm {set DAC color}
- mov dx, tableWriteIndex
- mov al, color
- out dx, al
- inc dx
- mov al, r
- out dx, al
- mov al, g
- out dx, al
- mov al, b
- out dx, al
- end; {Write index now points to next color}
-
- Function getColor(color : Byte) : LongInt; Assembler;
- Asm {get DAC color}
- mov dx, tableReadIndex
- mov al, color
- out dx, al
- add dx, 2
- cld
- xor bh, bh
- in al, dx
- mov bl, al
- in al, dx
- mov ah, al
- in al, dx
- mov dx, bx
- end; {read index now points to next color}
-
- Procedure setPalette(color : Byte; num : Word; Var rgb); Assembler;
- Asm
- mov cx, num
- jcxz @X
- mov ax, cx
- shl cx, 1
- add cx, ax {mul by 3}
- push ds
- lds si, rgb
- cld
- mov dx, tableWriteIndex
- mov al, color
- out dx, al
- inc dx
- @L:
- lodsb
- out dx, al
- loop @L
- pop ds
- @X:
- end;
-
- Procedure getPalette(color : Byte; num : Word; Var rgb); Assembler;
- Asm
- mov cx, num
- jcxz @X
- mov ax, cx
- shl cx, 1
- add cx, ax {mul by 3}
- les di, rgb
- cld
- mov dx, tableReadIndex
- mov al, color
- out dx, al
- add dx, 2
- @L:
- in al, dx
- stosb
- loop @L
- @X:
- end;
-
- {XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}
-
- Function vgaPresent : Boolean; Assembler;
- Asm
- mov ah, $F
- int $10
- mov oldMode, al { save old Gr mode}
- mov ax, $1A00
- int $10 { check For VGA}
- cmp al, $1A
- jne @ERR { no VGA Bios}
- cmp bl, 7
- jb @ERR { is VGA or better?}
- cmp bl, $FF
- jnz @OK
- @ERR:
- xor al, al
- jmp @EXIT
- @OK:
- mov al, 1
- @EXIT:
- end;
-
- Procedure Graphbegin;
- Var
- p : Array [0..255] of tRGB;
- i, j,
- k, l : Byte;
- begin
- Asm
- mov ax, $0013
- int $10
- end; {set BIOS mode}
-
- l := 0;
- For i := 0 to 5 do
- For j := 0 to 5 do
- For k := 0 to 5 do
- With p[l] do
- begin
- r := (i * 63) div 5;
- g := (j * 63) div 5;
- b := (k * 63) div 5;
- inc(l);
- end;
-
- For i := 216 to 255 do
- With p[i] do
- begin
- l := ((i - 216) * 63) div 39;
- r := l;
- g := l;
- b := l;
- end;
-
- setpalette(0, 256, p);
- color := 0;
-
- Asm
- mov dx, seqPort
- mov ax, $0604
- out dx, ax { disable chain 4}
- mov ax, $0100
- out dx, ax { synchronous reset asserted}
- dec dx
- dec dx
- mov al, $E3
- out dx, al { misc output port at $3C2}
- { use 25mHz dot clock, 480 lines}
- inc dx
- inc dx
- mov ax, $0300
- out dx, ax { restart sequencer}
- mov dx, CrtcPort
- mov al, $11
- out dx, al { select cr11}
- inc dx
- in al, dx
- and al, $7F
- out dx, al
- dec dx { remove Write protect from cr0-cr7}
- mov si, offset CrtcRegTable
- mov cx, CrtcRegLen
- repz outsw { set Crtc data}
- mov ax, vxBytes
- shr ax, 1 { Words per scan line}
- mov ah, al
- mov al, $13
- out dx, ax { set CrtC offset reg}
- end;
-
- clearGraph;
- end;
-
- Procedure Graphend; Far;
- begin
- ExitProc := exitSave;
- Asm
- mov al, oldMode
- mov ah, 0
- int $10
- end;
- end;
-
- begin
- CrtcPort := memw[$40 : $63];
- input1Port := CrtcPort + 6;
- if vgaPresent then
- begin
- ExitSave := exitProc;
- ExitProc := @Graphend;
- Graphbegin;
- end
- else
- begin
- Writeln(^G + 'VGA required.');
- halt(1);
- end;
- end.